We have been asked by a reviewer to provide details on why we did what we did in terms of clustering. Here, I want to try out a different clustering approach to see if we get overlapping clustering and how sensitive the cluster borders are to different paramters.

I thought I could try and use the Seurat workflow and ‘pretend’ that the magic table is sc RNAseq data. I have mainly been following this tutorial https://satijalab.org/seurat/articles/pbmc3k_tutorial.html

Loading libraries

library(Seurat)
Loading required package: SeuratObject
Loading required package: sp
‘SeuratObject’ was built under R 4.4.0 but the current version is 4.4.1; it is recomended that you
reinstall ‘SeuratObject’ as the ABI for R may have changed

Attaching package: ‘SeuratObject’

The following objects are masked from ‘package:base’:

    intersect, t

Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     ── Conflicts ───────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors

Importing the interaction pair data

read_tsv("../data/umap_mark_data_uncapped.txt") -> marks_import
Rows: 251254 Columns: 147── Column specification ───────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr   (7): interaction_ID, P_ID, PIR_ID, P_gene, PIR_gene, cluster_ID, cluster_group
dbl (140): UMAP1, UMAP2, CHiC_DNMT_KO_EpiLC_D2, CHiC_DNMT_KO_ES_D0, CHiC_DNMT_WT_EpiLC_D2, CHiC_DNMT_WT_ES_...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(marks_import)
colnames(marks_import)
  [1] "interaction_ID"                "UMAP1"                         "UMAP2"                        
  [4] "P_ID"                          "PIR_ID"                        "P_gene"                       
  [7] "PIR_gene"                      "CHiC_DNMT_KO_EpiLC_D2"         "CHiC_DNMT_KO_ES_D0"           
 [10] "CHiC_DNMT_WT_EpiLC_D2"         "CHiC_DNMT_WT_ES_D0"            "CHiC_TET_KO_EpiLC_D2"         
 [13] "CHiC_TET_KO_ES_D0"             "CHiC_TET_WT_EpiLC_D2"          "CHiC_TET_WT_ES_D0"            
 [16] "P_mC_DNMT_WT_ES_D0"            "P_mC_DNMT_WT_EpiLC_D2"         "P_mC_TET_WT_ES_D0"            
 [19] "P_mC_TET_WT_EpiLC_D2"          "P_mC_TET_KO_ES_D0"             "P_mC_TET_KO_EpiLC_D2"         
 [22] "PIR_mC_DNMT_WT_ES_D0"          "PIR_mC_DNMT_WT_EpiLC_D2"       "PIR_mC_TET_WT_ES_D0"          
 [25] "PIR_mC_TET_WT_EpiLC_D2"        "PIR_mC_TET_KO_ES_D0"           "PIR_mC_TET_KO_EpiLC_D2"       
 [28] "P_hmC_TET_WT_ES_D0"            "P_hmC_TET_WT_EpiLC_D2"         "P_hmC_DNMT_WT_EpiLC_D2"       
 [31] "P_ATAC_DNMT_KO_EpiLC_D2"       "P_ATAC_DNMT_KO_ES_D0"          "P_ATAC_DNMT_WT_EpiLC_D2"      
 [34] "P_ATAC_DNMT_WT_ES_D0"          "P_ATAC_TET_KO_EpiLC_D2"        "P_ATAC_TET_KO_ES_D0"          
 [37] "P_ATAC_TET_WT_EpiLC_D2"        "P_ATAC_TET_WT_ES_D0"           "P_CTCF_DNMT_KO_EpiLC_D2"      
 [40] "P_CTCF_DNMT_KO_ES_D0"          "P_CTCF_DNMT_WT_EpiLC_D2"       "P_CTCF_DNMT_WT_ES_D0"         
 [43] "P_CTCF_TET_KO_EpiLC_D2"        "P_CTCF_TET_KO_ES_D0"           "P_CTCF_TET_WT_EpiLC_D2"       
 [46] "P_CTCF_TET_WT_ES_D0"           "P_H3K27ac_DNMT_KO_EpiLC_D2"    "P_H3K27ac_DNMT_KO_ES_D0"      
 [49] "P_H3K27ac_DNMT_WT_EpiLC_D2"    "P_H3K27ac_DNMT_WT_ES_D0"       "P_H3K27ac_TET_KO_EpiLC_D2"    
 [52] "P_H3K27ac_TET_KO_ES_D0"        "P_H3K27ac_TET_WT_EpiLC_D2"     "P_H3K27ac_TET_WT_ES_D0"       
 [55] "P_H3K27me3_DNMT_KO_EpiLC_D2"   "P_H3K27me3_DNMT_KO_ES_D0"      "P_H3K27me3_DNMT_WT_EpiLC_D2"  
 [58] "P_H3K27me3_DNMT_WT_ES_D0"      "P_H3K27me3_TET_KO_EpiLC_D2"    "P_H3K27me3_TET_KO_ES_D0"      
 [61] "P_H3K27me3_TET_WT_EpiLC_D2"    "P_H3K27me3_TET_WT_ES_D0"       "P_H3K4me1_DNMT_KO_EpiLC_D2"   
 [64] "P_H3K4me1_DNMT_KO_ES_D0"       "P_H3K4me1_DNMT_WT_EpiLC_D2"    "P_H3K4me1_DNMT_WT_ES_D0"      
 [67] "P_H3K4me1_TET_KO_EpiLC_D2"     "P_H3K4me1_TET_KO_ES_D0"        "P_H3K4me1_TET_WT_EpiLC_D2"    
 [70] "P_H3K4me1_TET_WT_ES_D0"        "P_H3K4me3_DNMT_KO_EpiLC_D2"    "P_H3K4me3_DNMT_KO_ES_D0"      
 [73] "P_H3K4me3_DNMT_WT_EpiLC_D2"    "P_H3K4me3_DNMT_WT_ES_D0"       "P_H3K4me3_TET_KO_EpiLC_D2"    
 [76] "P_H3K4me3_TET_KO_ES_D0"        "P_H3K4me3_TET_WT_EpiLC_D2"     "P_H3K4me3_TET_WT_ES_D0"       
 [79] "P_Input_DNMT_KO_EpiLC_D2"      "P_Input_DNMT_KO_ES_D0"         "P_Input_DNMT_WT_EpiLC_D2"     
 [82] "P_Input_DNMT_WT_ES_D0"         "P_Input_TET_KO_EpiLC_D2"       "P_Input_TET_KO_ES_D0"         
 [85] "P_Input_TET_WT_EpiLC_D2"       "P_Input_TET_WT_ES_D0"          "PIR_hmC_TET_WT_ES_D0"         
 [88] "PIR_hmC_TET_WT_EpiLC_D2"       "PIR_hmC_DNMT_WT_EpiLC_D2"      "PIR_ATAC_DNMT_KO_EpiLC_D2"    
 [91] "PIR_ATAC_DNMT_KO_ES_D0"        "PIR_ATAC_DNMT_WT_EpiLC_D2"     "PIR_ATAC_DNMT_WT_ES_D0"       
 [94] "PIR_ATAC_TET_KO_EpiLC_D2"      "PIR_ATAC_TET_KO_ES_D0"         "PIR_ATAC_TET_WT_EpiLC_D2"     
 [97] "PIR_ATAC_TET_WT_ES_D0"         "PIR_CTCF_DNMT_KO_EpiLC_D2"     "PIR_CTCF_DNMT_KO_ES_D0"       
[100] "PIR_CTCF_DNMT_WT_EpiLC_D2"     "PIR_CTCF_DNMT_WT_ES_D0"        "PIR_CTCF_TET_KO_EpiLC_D2"     
[103] "PIR_CTCF_TET_KO_ES_D0"         "PIR_CTCF_TET_WT_EpiLC_D2"      "PIR_CTCF_TET_WT_ES_D0"        
[106] "PIR_H3K27ac_DNMT_KO_EpiLC_D2"  "PIR_H3K27ac_DNMT_KO_ES_D0"     "PIR_H3K27ac_DNMT_WT_EpiLC_D2" 
[109] "PIR_H3K27ac_DNMT_WT_ES_D0"     "PIR_H3K27ac_TET_KO_EpiLC_D2"   "PIR_H3K27ac_TET_KO_ES_D0"     
[112] "PIR_H3K27ac_TET_WT_EpiLC_D2"   "PIR_H3K27ac_TET_WT_ES_D0"      "PIR_H3K27me3_DNMT_KO_EpiLC_D2"
[115] "PIR_H3K27me3_DNMT_KO_ES_D0"    "PIR_H3K27me3_DNMT_WT_EpiLC_D2" "PIR_H3K27me3_DNMT_WT_ES_D0"   
[118] "PIR_H3K27me3_TET_KO_EpiLC_D2"  "PIR_H3K27me3_TET_KO_ES_D0"     "PIR_H3K27me3_TET_WT_EpiLC_D2" 
[121] "PIR_H3K27me3_TET_WT_ES_D0"     "PIR_H3K4me1_DNMT_KO_EpiLC_D2"  "PIR_H3K4me1_DNMT_KO_ES_D0"    
[124] "PIR_H3K4me1_DNMT_WT_EpiLC_D2"  "PIR_H3K4me1_DNMT_WT_ES_D0"     "PIR_H3K4me1_TET_KO_EpiLC_D2"  
[127] "PIR_H3K4me1_TET_KO_ES_D0"      "PIR_H3K4me1_TET_WT_EpiLC_D2"   "PIR_H3K4me1_TET_WT_ES_D0"     
[130] "PIR_H3K4me3_DNMT_KO_EpiLC_D2"  "PIR_H3K4me3_DNMT_KO_ES_D0"     "PIR_H3K4me3_DNMT_WT_EpiLC_D2" 
[133] "PIR_H3K4me3_DNMT_WT_ES_D0"     "PIR_H3K4me3_TET_KO_EpiLC_D2"   "PIR_H3K4me3_TET_KO_ES_D0"     
[136] "PIR_H3K4me3_TET_WT_EpiLC_D2"   "PIR_H3K4me3_TET_WT_ES_D0"      "PIR_Input_DNMT_KO_EpiLC_D2"   
[139] "PIR_Input_DNMT_KO_ES_D0"       "PIR_Input_DNMT_WT_EpiLC_D2"    "PIR_Input_DNMT_WT_ES_D0"      
[142] "PIR_Input_TET_KO_EpiLC_D2"     "PIR_Input_TET_KO_ES_D0"        "PIR_Input_TET_WT_EpiLC_D2"    
[145] "PIR_Input_TET_WT_ES_D0"        "cluster_ID"                    "cluster_group"                

Retaining only the columns that should go into clustering

marks_import %>% 
  select(-contains("UMAP"), -P_ID, -PIR_ID, -P_gene, -PIR_gene, -contains("Input"), -cluster_ID, -cluster_group) %>% # the labels and marks I don't want
  select(-contains("DNMT"), -contains("ES"), -contains("KO")) -> marks # limiting to Epi and TET and WT
head(marks)

Transposing this so it can be made into a Seurat object

marks %>% 
  column_to_rownames(var = "interaction_ID") %>% 
  t() %>% 
  as.data.frame() -> marks_transposed

head(marks_transposed)

Making this into a Seurat object

CreateSeuratObject(counts = marks_transposed, assay = "mark") -> marks_Seurat
Warning: Feature names cannot have underscores ('_'), replacing with dashes ('-')Warning: Data is of class data.frame. Coercing to dgCMatrix.

LogNormalising the values

marks_normalised <- NormalizeData(marks_Seurat)
Normalizing layer: counts
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

Scaling the data

all.marks <- rownames(marks_normalised)
marks_scaled <- ScaleData(marks_normalised, features = all.marks)
Centering and scaling data matrix

  |                                                                                                                                                        
  |                                                                                                                                                  |   0%
  |                                                                                                                                                        
  |==================================================================================================================================================| 100%

performing linear dimensional reduction

marks_PCA <- RunPCA(marks_scaled, features = all.marks)
Warning: You're computing too large a percentage of total singular values, use a standard svd instead.Warning: Requested number is larger than the number of available items (17). Setting to 17.Warning: Requested number is larger than the number of available items (17). Setting to 17.Warning: Requested number is larger than the number of available items (17). Setting to 17.Warning: Requested number is larger than the number of available items (17). Setting to 17.Warning: Requested number is larger than the number of available items (17). Setting to 17.PC_ 1 
Positive:  P-H3K27ac-TET-WT-EpiLC-D2, P-H3K4me1-TET-WT-EpiLC-D2, P-ATAC-TET-WT-EpiLC-D2, P-H3K4me3-TET-WT-EpiLC-D2, PIR-H3K27ac-TET-WT-EpiLC-D2, PIR-H3K4me1-TET-WT-EpiLC-D2, PIR-ATAC-TET-WT-EpiLC-D2, PIR-H3K4me3-TET-WT-EpiLC-D2 
Negative:  P-mC-TET-WT-EpiLC-D2, PIR-mC-TET-WT-EpiLC-D2, PIR-H3K27me3-TET-WT-EpiLC-D2, P-H3K27me3-TET-WT-EpiLC-D2, CHiC-TET-WT-EpiLC-D2, P-hmC-TET-WT-EpiLC-D2, PIR-hmC-TET-WT-EpiLC-D2, PIR-CTCF-TET-WT-EpiLC-D2 
PC_ 2 
Positive:  PIR-H3K4me3-TET-WT-EpiLC-D2, P-mC-TET-WT-EpiLC-D2, PIR-ATAC-TET-WT-EpiLC-D2, PIR-H3K27ac-TET-WT-EpiLC-D2, PIR-H3K4me1-TET-WT-EpiLC-D2, PIR-CTCF-TET-WT-EpiLC-D2, P-hmC-TET-WT-EpiLC-D2, PIR-hmC-TET-WT-EpiLC-D2 
Negative:  PIR-mC-TET-WT-EpiLC-D2, P-H3K4me3-TET-WT-EpiLC-D2, P-ATAC-TET-WT-EpiLC-D2, P-H3K27ac-TET-WT-EpiLC-D2, P-H3K4me1-TET-WT-EpiLC-D2, P-CTCF-TET-WT-EpiLC-D2, P-H3K27me3-TET-WT-EpiLC-D2, CHiC-TET-WT-EpiLC-D2 
PC_ 3 
Positive:  P-H3K27me3-TET-WT-EpiLC-D2, PIR-H3K27me3-TET-WT-EpiLC-D2, P-hmC-TET-WT-EpiLC-D2, P-CTCF-TET-WT-EpiLC-D2, PIR-CTCF-TET-WT-EpiLC-D2, P-H3K4me1-TET-WT-EpiLC-D2, PIR-hmC-TET-WT-EpiLC-D2, P-mC-TET-WT-EpiLC-D2 
Negative:  P-H3K27ac-TET-WT-EpiLC-D2, PIR-H3K27ac-TET-WT-EpiLC-D2, PIR-H3K4me3-TET-WT-EpiLC-D2, P-H3K4me3-TET-WT-EpiLC-D2, PIR-H3K4me1-TET-WT-EpiLC-D2, P-ATAC-TET-WT-EpiLC-D2, PIR-ATAC-TET-WT-EpiLC-D2, CHiC-TET-WT-EpiLC-D2 
PC_ 4 
Positive:  PIR-H3K27me3-TET-WT-EpiLC-D2, PIR-CTCF-TET-WT-EpiLC-D2, P-H3K27me3-TET-WT-EpiLC-D2, PIR-ATAC-TET-WT-EpiLC-D2, P-CTCF-TET-WT-EpiLC-D2, P-ATAC-TET-WT-EpiLC-D2, PIR-H3K4me3-TET-WT-EpiLC-D2, CHiC-TET-WT-EpiLC-D2 
Negative:  PIR-hmC-TET-WT-EpiLC-D2, P-hmC-TET-WT-EpiLC-D2, PIR-mC-TET-WT-EpiLC-D2, PIR-H3K4me1-TET-WT-EpiLC-D2, P-H3K4me1-TET-WT-EpiLC-D2, P-mC-TET-WT-EpiLC-D2, PIR-H3K27ac-TET-WT-EpiLC-D2, P-H3K27ac-TET-WT-EpiLC-D2 
PC_ 5 
Positive:  PIR-hmC-TET-WT-EpiLC-D2, PIR-mC-TET-WT-EpiLC-D2, PIR-H3K27me3-TET-WT-EpiLC-D2, PIR-CTCF-TET-WT-EpiLC-D2, PIR-H3K4me1-TET-WT-EpiLC-D2, CHiC-TET-WT-EpiLC-D2, PIR-ATAC-TET-WT-EpiLC-D2, P-H3K27me3-TET-WT-EpiLC-D2 
Negative:  P-hmC-TET-WT-EpiLC-D2, P-H3K4me1-TET-WT-EpiLC-D2, P-mC-TET-WT-EpiLC-D2, P-CTCF-TET-WT-EpiLC-D2, P-ATAC-TET-WT-EpiLC-D2, PIR-H3K4me3-TET-WT-EpiLC-D2, P-H3K27ac-TET-WT-EpiLC-D2, PIR-H3K27ac-TET-WT-EpiLC-D2 

The warnings here are ok, it just complains that it doesn’t have enough dimensions and automatically reduces them to 17.

DimPlot(marks_PCA, reduction = "pca", raster = FALSE)

#DimHeatmap(marks_PCA, dims = 1:5, balanced = TRUE)
ElbowPlot(marks_PCA)
Warning: The object only has information for 16 reductions

It’s hard to determine a cutoff for PCAs to use, I tried 8, 9 and 12 to check the clustering.

Clustering

-> KNN graph based on euclidean distance in PCA space with edge weights between samples by Jaccard similarity (overlap in local neighbourhoods) -> Louvain clustering

marks_KNN <- FindNeighbors(marks_PCA, dims = 1:12)
Computing nearest neighbor graph
Computing SNN
marks_Louvain <- FindClusters(marks_KNN, resolution = 1)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 251254
Number of edges: 5958936

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8286
Number of communities: 31
Elapsed time: 180 seconds

I ran several iterations with different parameters to check what made the most sense with the UMAP representation. dim 9, resolution 0.8 dim 9, resolution 1.2 dim 15, resolution 1 dim 12, resolution 1 (this is the one I settled on)

Look at cluster IDs

Idents(marks_Louvain) %>% 
  as.data.frame() %>% 
  rownames_to_column(var = "interaction_ID") %>% 
  rename(Louvain_cluster_ID = ".") -> Louvain_clusters
head(Louvain_clusters)

Now incorporating this info in the original table

marks_import %>% 
  left_join(Louvain_clusters) -> marks_2
Joining with `by = join_by(interaction_ID)`
head(marks_2)

Plotting the original clusters

marks_2 %>% 
  slice_sample(prop = 0.1) %>% 
  ggplot(aes(UMAP1, UMAP2, colour = cluster_ID)) +
  geom_point(size = 0.5) +
  theme_bw(base_size = 14) +
  ggtitle("EM clusters") +
  coord_cartesian(xlim = c(-10, 12), ylim = c(-10, 8)) +
  theme(aspect.ratio = 1, plot.title = element_text(hjust = 0.5))

Plotting the Louvain clusters

marks_2 %>% 
  slice_sample(prop = 0.05) %>% 
  ggplot(aes(UMAP1, UMAP2, colour = Louvain_cluster_ID)) +
  geom_point(size = 0.5) +
  geom_point(data = marks_2 %>% slice_sample(prop = 0.05) %>% filter(Louvain_cluster_ID == 19), size = 0.5, colour = "black") +
  theme_bw(base_size = 14) +
  ggtitle("Louvain clusters") +
  coord_cartesian(xlim = c(-10, 12), ylim = c(-10, 8)) +
  theme(aspect.ratio = 1, plot.title = element_text(hjust = 0.5))

Okay, let’s explore these a bit more.

How many regions per cluster?

marks_2 %>% 
  group_by(Louvain_cluster_ID) %>% 
  count()

Looking at marks per cluster

marks_2 %>% 
  select(-UMAP1, -UMAP2, -P_ID, -PIR_ID, -P_gene, -PIR_gene, -contains("DNMT"), -contains("ES"), -contains("Input"), -contains("KO"), -contains("CHiC")) %>% 
  select(interaction_ID, cluster_ID, cluster_group, Louvain_cluster_ID, everything()) %>% 
  pivot_longer(5:last_col(), names_to = "condition", values_to = "values") %>% 
  separate(condition, into = c("region", "mark")) -> marks_TET_Epi_long
Warning: Expected 2 pieces. Additional pieces discarded in 4020064 rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].

The warning here is fine, I deliberately discard the additional pieces.

Clusters to exclude (the ones with fewer than 1000 data points)

excluded_clusters <- c("21", "22", "23", "24", "25", "26", "27", "28", "29", "30")

Plotting boxplots

# marks_TET_Epi_long %>% 
#   filter(mark != "mC") %>% 
#   filter(!Louvain_cluster_ID %in% excluded_clusters) %>% 
#   ggplot(aes(Louvain_cluster_ID, values, fill = region)) +
#   geom_boxplot(outlier.shape = NA) +
#   ylim(0, 8) +
#   theme_bw(base_size = 14) +
#   facet_grid(rows = "mark")

Boxplots per cluster

marks_TET_Epi_long %>% 
  filter(mark != "mC") %>% 
  filter(!Louvain_cluster_ID %in% excluded_clusters) %>% 
  ggplot(aes(mark, values, fill = region)) +
  geom_boxplot(outlier.shape = NA) +
  ylim(0, 8) +
  theme_bw(base_size = 14) +
  facet_grid(rows = "Louvain_cluster_ID")

I then summarised the clusters according to their marks (and their presumed biological function).

Summarised clusters

cluster_group_names <- c("active P - unmarked PIR",
                        "active P - low primed E",
                        "PC P - unmarked PIR",
                        "inactive P - unmarked PIR",
                        "inactive P - low primed E, CTCF",
                        "primed E",
                        "poised E",
                        "active P - active P",
                        "active P - active E"
                        )
cluster_group_colours <- c("#b785bb", "#53c2b3", "#bf6c6c", "#b2b5b5", "#741113", "#eaca48", "#ca3526", "#91c740", "#252d37")
names(cluster_group_colours) <- cluster_group_names

Plotting original summarised marks


marks_2 %>% 
  mutate(cluster_group = gsub("inactive P - low primed E", "active P - low primed E", cluster_group)) %>% 
  mutate(cluster_group = gsub("active P - low primed E, CTCF", "inactive P - low primed E, CTCF", cluster_group)) %>% 
  slice_sample(prop = 0.1) %>% 
  ggplot(aes(UMAP1, UMAP2, colour = cluster_group)) +
  geom_point(size = 0.5) +
  theme_bw(base_size = 14) +
  ggtitle("EM clusters") +
  coord_cartesian(xlim = c(-10, 12), ylim = c(-10, 8)) +
  scale_colour_manual(values = cluster_group_colours) +
  theme(aspect.ratio = 1, plot.title = element_text(hjust = 0.5)) -> UMAP_EM_clusters

UMAP_EM_clusters

Summarising Louvain clusters (This one is for dim 12, resolution 1)

P_unmarkedPIR <- c("2", "5", "13", "15")
active_lowprimed <- c("9", "16")
PC_P_unmarked <- c("0", "12", "17")
inactive_unmarked <- c("3", "4", "7", "9", "10", "14")
inactive_lowprimedCTCF <- c("1", "19")
primed <- c("20", "6")
poised <- c( "18")
p_p <- c("11")
active_activeE <- c("8")
marks_2 %>% 
  filter(!Louvain_cluster_ID %in% excluded_clusters) %>% 
  mutate(Louvain_cluster_group = case_when(Louvain_cluster_ID %in% P_unmarkedPIR ~ "active P - unmarked PIR",
                                           Louvain_cluster_ID %in% active_lowprimed ~ "active P - low primed E",
                                           Louvain_cluster_ID %in% PC_P_unmarked ~ "PC P - unmarked PIR",
                                           Louvain_cluster_ID %in% inactive_unmarked ~ "inactive P - unmarked PIR",
                                           Louvain_cluster_ID %in% inactive_lowprimedCTCF ~ "inactive P - low primed E, CTCF",
                                           Louvain_cluster_ID %in% primed ~ "primed E",
                                           Louvain_cluster_ID %in% poised ~ "poised E",
                                           Louvain_cluster_ID %in% p_p ~ "active P - active P",
                                           Louvain_cluster_ID %in% active_activeE ~ "active P - active E")) -> marks_3

Plotting Louvain summarised marks

marks_3 %>% 
  slice_sample(prop = 0.05) %>% 
  ggplot(aes(UMAP1, UMAP2, colour = Louvain_cluster_group)) +
  geom_point(size = 0.5) +
  theme_bw(base_size = 14) +
  ggtitle("Louvain clusters") +
  coord_cartesian(xlim = c(-10, 12), ylim = c(-10, 8)) +
  scale_colour_manual(values = cluster_group_colours) +
  theme(aspect.ratio = 1, plot.title = element_text(hjust = 0.5), legend.title = element_blank()) -> UMAP_Louvain_clusters

UMAP_Louvain_clusters

Exporting

ggsave("../output/plots/UMAP_Louvain_clusters.png", UMAP_Louvain_clusters, height = 4, width = 8, units = "in")
ggsave("../output/plots/UMAP_Louvain_clusters.svg", UMAP_Louvain_clusters, height = 4, width = 8, units = "in")
Error in loadNamespace(x) : there is no package called ‘svglite’

Some clusters are strong and essentially pop up in all cluster conditions:

Exporting the clusters

LS0tCnRpdGxlOiAiQWx0ZXJuYXRpdmUgY2x1c3RlcmluZyBmb3IgUGxleCBkYXRhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpXZSBoYXZlIGJlZW4gYXNrZWQgYnkgYSByZXZpZXdlciB0byBwcm92aWRlIGRldGFpbHMgb24gd2h5IHdlIGRpZCB3aGF0IHdlIGRpZCBpbiB0ZXJtcyBvZiBjbHVzdGVyaW5nLiBIZXJlLCBJIHdhbnQgdG8gdHJ5IG91dCBhIGRpZmZlcmVudCBjbHVzdGVyaW5nIGFwcHJvYWNoIHRvIHNlZSBpZiB3ZSBnZXQgb3ZlcmxhcHBpbmcgY2x1c3RlcmluZyBhbmQgaG93IHNlbnNpdGl2ZSB0aGUgY2x1c3RlciBib3JkZXJzIGFyZSB0byBkaWZmZXJlbnQgcGFyYW10ZXJzLgoKSSB0aG91Z2h0IEkgY291bGQgdHJ5IGFuZCB1c2UgdGhlIFNldXJhdCB3b3JrZmxvdyBhbmQgJ3ByZXRlbmQnIHRoYXQgdGhlIG1hZ2ljIHRhYmxlIGlzIHNjIFJOQXNlcSBkYXRhLgpJIGhhdmUgbWFpbmx5IGJlZW4gZm9sbG93aW5nIHRoaXMgdHV0b3JpYWwgaHR0cHM6Ly9zYXRpamFsYWIub3JnL3NldXJhdC9hcnRpY2xlcy9wYm1jM2tfdHV0b3JpYWwuaHRtbAoKTG9hZGluZyBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKSW1wb3J0aW5nIHRoZSBpbnRlcmFjdGlvbiBwYWlyIGRhdGEKCmBgYHtyfQpyZWFkX3RzdigiLi4vZGF0YS91bWFwX21hcmtfZGF0YV91bmNhcHBlZC50eHQiKSAtPiBtYXJrc19pbXBvcnQKaGVhZChtYXJrc19pbXBvcnQpCmNvbG5hbWVzKG1hcmtzX2ltcG9ydCkKYGBgClJldGFpbmluZyBvbmx5IHRoZSBjb2x1bW5zIHRoYXQgc2hvdWxkIGdvIGludG8gY2x1c3RlcmluZwoKYGBge3J9Cm1hcmtzX2ltcG9ydCAlPiUgCiAgc2VsZWN0KC1jb250YWlucygiVU1BUCIpLCAtUF9JRCwgLVBJUl9JRCwgLVBfZ2VuZSwgLVBJUl9nZW5lLCAtY29udGFpbnMoIklucHV0IiksIC1jbHVzdGVyX0lELCAtY2x1c3Rlcl9ncm91cCkgJT4lICMgdGhlIGxhYmVscyBhbmQgbWFya3MgSSBkb24ndCB3YW50CiAgc2VsZWN0KC1jb250YWlucygiRE5NVCIpLCAtY29udGFpbnMoIkVTIiksIC1jb250YWlucygiS08iKSkgLT4gbWFya3MgIyBsaW1pdGluZyB0byBFcGkgYW5kIFRFVCBhbmQgV1QKaGVhZChtYXJrcykKYGBgClRyYW5zcG9zaW5nIHRoaXMgc28gaXQgY2FuIGJlIG1hZGUgaW50byBhIFNldXJhdCBvYmplY3QKCmBgYHtyfQptYXJrcyAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJpbnRlcmFjdGlvbl9JRCIpICU+JSAKICB0KCkgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAtPiBtYXJrc190cmFuc3Bvc2VkCgpoZWFkKG1hcmtzX3RyYW5zcG9zZWQpCmBgYAoKCk1ha2luZyB0aGlzIGludG8gYSBTZXVyYXQgb2JqZWN0CgpgYGB7cn0KQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IG1hcmtzX3RyYW5zcG9zZWQsIGFzc2F5ID0gIm1hcmsiKSAtPiBtYXJrc19TZXVyYXQKYGBgCgpMb2dOb3JtYWxpc2luZyB0aGUgdmFsdWVzCgpgYGB7cn0KbWFya3Nfbm9ybWFsaXNlZCA8LSBOb3JtYWxpemVEYXRhKG1hcmtzX1NldXJhdCkKYGBgCgpTY2FsaW5nIHRoZSBkYXRhCgpgYGB7cn0KYWxsLm1hcmtzIDwtIHJvd25hbWVzKG1hcmtzX25vcm1hbGlzZWQpCm1hcmtzX3NjYWxlZCA8LSBTY2FsZURhdGEobWFya3Nfbm9ybWFsaXNlZCwgZmVhdHVyZXMgPSBhbGwubWFya3MpCmBgYAoKcGVyZm9ybWluZyBsaW5lYXIgZGltZW5zaW9uYWwgcmVkdWN0aW9uCgpgYGB7cn0KbWFya3NfUENBIDwtIFJ1blBDQShtYXJrc19zY2FsZWQsIGZlYXR1cmVzID0gYWxsLm1hcmtzKQpgYGAKClRoZSB3YXJuaW5ncyBoZXJlIGFyZSBvaywgaXQganVzdCBjb21wbGFpbnMgdGhhdCBpdCBkb2Vzbid0IGhhdmUgZW5vdWdoIGRpbWVuc2lvbnMgYW5kIGF1dG9tYXRpY2FsbHkgcmVkdWNlcyB0aGVtIHRvIDE3LgpgYGB7cn0KRGltUGxvdChtYXJrc19QQ0EsIHJlZHVjdGlvbiA9ICJwY2EiLCByYXN0ZXIgPSBGQUxTRSkKYGBgCgpgYGB7cn0KI0RpbUhlYXRtYXAobWFya3NfUENBLCBkaW1zID0gMTo1LCBiYWxhbmNlZCA9IFRSVUUpCmBgYAoKCmBgYHtyfQpFbGJvd1Bsb3QobWFya3NfUENBKQpgYGAKSXQncyBoYXJkIHRvIGRldGVybWluZSBhIGN1dG9mZiBmb3IgUENBcyB0byB1c2UsIEkgdHJpZWQgOCwgOSBhbmQgMTIgdG8gY2hlY2sgdGhlIGNsdXN0ZXJpbmcuCgpDbHVzdGVyaW5nCgotPiBLTk4gZ3JhcGggYmFzZWQgb24gZXVjbGlkZWFuIGRpc3RhbmNlIGluIFBDQSBzcGFjZSB3aXRoIGVkZ2Ugd2VpZ2h0cyBiZXR3ZWVuIHNhbXBsZXMgYnkgSmFjY2FyZCBzaW1pbGFyaXR5IChvdmVybGFwIGluIGxvY2FsIG5laWdoYm91cmhvb2RzKQotPiBMb3V2YWluIGNsdXN0ZXJpbmcgCgpgYGB7cn0KbWFya3NfS05OIDwtIEZpbmROZWlnaGJvcnMobWFya3NfUENBLCBkaW1zID0gMToxMikKbWFya3NfTG91dmFpbiA8LSBGaW5kQ2x1c3RlcnMobWFya3NfS05OLCByZXNvbHV0aW9uID0gMSkKYGBgCgpJIHJhbiBzZXZlcmFsIGl0ZXJhdGlvbnMgd2l0aCBkaWZmZXJlbnQgcGFyYW1ldGVycyB0byBjaGVjayB3aGF0IG1hZGUgdGhlIG1vc3Qgc2Vuc2Ugd2l0aCB0aGUgVU1BUCByZXByZXNlbnRhdGlvbi4KZGltIDksIHJlc29sdXRpb24gMC44CmRpbSA5LCByZXNvbHV0aW9uIDEuMgpkaW0gMTUsIHJlc29sdXRpb24gMQpkaW0gMTIsIHJlc29sdXRpb24gMSAodGhpcyBpcyB0aGUgb25lIEkgc2V0dGxlZCBvbikKCgpMb29rIGF0IGNsdXN0ZXIgSURzCgpgYGB7cn0KSWRlbnRzKG1hcmtzX0xvdXZhaW4pICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiaW50ZXJhY3Rpb25fSUQiKSAlPiUgCiAgcmVuYW1lKExvdXZhaW5fY2x1c3Rlcl9JRCA9ICIuIikgLT4gTG91dmFpbl9jbHVzdGVycwpoZWFkKExvdXZhaW5fY2x1c3RlcnMpCmBgYAoKTm93IGluY29ycG9yYXRpbmcgdGhpcyBpbmZvIGluIHRoZSBvcmlnaW5hbCB0YWJsZQoKYGBge3J9Cm1hcmtzX2ltcG9ydCAlPiUgCiAgbGVmdF9qb2luKExvdXZhaW5fY2x1c3RlcnMpIC0+IG1hcmtzXzIKaGVhZChtYXJrc18yKQpgYGAKClBsb3R0aW5nIHRoZSBvcmlnaW5hbCBjbHVzdGVycwoKYGBge3J9Cm1hcmtzXzIgJT4lIAogIHNsaWNlX3NhbXBsZShwcm9wID0gMC4xKSAlPiUgCiAgZ2dwbG90KGFlcyhVTUFQMSwgVU1BUDIsIGNvbG91ciA9IGNsdXN0ZXJfSUQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsKICBnZ3RpdGxlKCJFTSBjbHVzdGVycyIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTEwLCAxMiksIHlsaW0gPSBjKC0xMCwgOCkpICsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgClBsb3R0aW5nIHRoZSBMb3V2YWluIGNsdXN0ZXJzCgpgYGB7cn0KbWFya3NfMiAlPiUgCiAgc2xpY2Vfc2FtcGxlKHByb3AgPSAwLjA1KSAlPiUgCiAgZ2dwbG90KGFlcyhVTUFQMSwgVU1BUDIsIGNvbG91ciA9IExvdXZhaW5fY2x1c3Rlcl9JRCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtYXJrc18yICU+JSBzbGljZV9zYW1wbGUocHJvcCA9IDAuMDUpICU+JSBmaWx0ZXIoTG91dmFpbl9jbHVzdGVyX0lEID09IDE5KSwgc2l6ZSA9IDAuNSwgY29sb3VyID0gImJsYWNrIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2d0aXRsZSgiTG91dmFpbiBjbHVzdGVycyIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTEwLCAxMiksIHlsaW0gPSBjKC0xMCwgOCkpICsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgpPa2F5LCBsZXQncyBleHBsb3JlIHRoZXNlIGEgYml0IG1vcmUuCgpIb3cgbWFueSByZWdpb25zIHBlciBjbHVzdGVyPwoKYGBge3J9Cm1hcmtzXzIgJT4lIAogIGdyb3VwX2J5KExvdXZhaW5fY2x1c3Rlcl9JRCkgJT4lIAogIGNvdW50KCkKYGBgCkxvb2tpbmcgYXQgbWFya3MgcGVyIGNsdXN0ZXIKCmBgYHtyfQptYXJrc18yICU+JSAKICBzZWxlY3QoLVVNQVAxLCAtVU1BUDIsIC1QX0lELCAtUElSX0lELCAtUF9nZW5lLCAtUElSX2dlbmUsIC1jb250YWlucygiRE5NVCIpLCAtY29udGFpbnMoIkVTIiksIC1jb250YWlucygiSW5wdXQiKSwgLWNvbnRhaW5zKCJLTyIpLCAtY29udGFpbnMoIkNIaUMiKSkgJT4lIAogIHNlbGVjdChpbnRlcmFjdGlvbl9JRCwgY2x1c3Rlcl9JRCwgY2x1c3Rlcl9ncm91cCwgTG91dmFpbl9jbHVzdGVyX0lELCBldmVyeXRoaW5nKCkpICU+JSAKICBwaXZvdF9sb25nZXIoNTpsYXN0X2NvbCgpLCBuYW1lc190byA9ICJjb25kaXRpb24iLCB2YWx1ZXNfdG8gPSAidmFsdWVzIikgJT4lIAogIHNlcGFyYXRlKGNvbmRpdGlvbiwgaW50byA9IGMoInJlZ2lvbiIsICJtYXJrIikpIC0+IG1hcmtzX1RFVF9FcGlfbG9uZwpgYGAKVGhlIHdhcm5pbmcgaGVyZSBpcyBmaW5lLCBJIGRlbGliZXJhdGVseSBkaXNjYXJkIHRoZSBhZGRpdGlvbmFsIHBpZWNlcy4KCkNsdXN0ZXJzIHRvIGV4Y2x1ZGUgKHRoZSBvbmVzIHdpdGggZmV3ZXIgdGhhbiAxMDAwIGRhdGEgcG9pbnRzKQoKYGBge3J9CmV4Y2x1ZGVkX2NsdXN0ZXJzIDwtIGMoIjIxIiwgIjIyIiwgIjIzIiwgIjI0IiwgIjI1IiwgIjI2IiwgIjI3IiwgIjI4IiwgIjI5IiwgIjMwIikKYGBgCgoKUGxvdHRpbmcgYm94cGxvdHMgCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGggPSA0fQojIG1hcmtzX1RFVF9FcGlfbG9uZyAlPiUgCiMgICBmaWx0ZXIobWFyayAhPSAibUMiKSAlPiUgCiMgICBmaWx0ZXIoIUxvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIGV4Y2x1ZGVkX2NsdXN0ZXJzKSAlPiUgCiMgICBnZ3Bsb3QoYWVzKExvdXZhaW5fY2x1c3Rlcl9JRCwgdmFsdWVzLCBmaWxsID0gcmVnaW9uKSkgKwojICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwojICAgeWxpbSgwLCA4KSArCiMgICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKwojICAgZmFjZXRfZ3JpZChyb3dzID0gIm1hcmsiKQpgYGAKCgpCb3hwbG90cyBwZXIgY2x1c3RlcgoKYGBge3IsIGZpZy5oZWlnaHQ9MTcsIGZpZy53aWR0aCA9IDEwfQptYXJrc19URVRfRXBpX2xvbmcgJT4lIAogIGZpbHRlcihtYXJrICE9ICJtQyIpICU+JSAKICBmaWx0ZXIoIUxvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIGV4Y2x1ZGVkX2NsdXN0ZXJzKSAlPiUgCiAgZ2dwbG90KGFlcyhtYXJrLCB2YWx1ZXMsIGZpbGwgPSByZWdpb24pKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIHlsaW0oMCwgOCkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgZmFjZXRfZ3JpZChyb3dzID0gIkxvdXZhaW5fY2x1c3Rlcl9JRCIpCmBgYApJIHRoZW4gc3VtbWFyaXNlZCB0aGUgY2x1c3RlcnMgYWNjb3JkaW5nIHRvIHRoZWlyIG1hcmtzIChhbmQgdGhlaXIgcHJlc3VtZWQgYmlvbG9naWNhbCBmdW5jdGlvbikuCgoKU3VtbWFyaXNlZCBjbHVzdGVycwoKYGBge3J9CmNsdXN0ZXJfZ3JvdXBfbmFtZXMgPC0gYygiYWN0aXZlIFAgLSB1bm1hcmtlZCBQSVIiLAogICAgICAgICAgICAgICAgICAgICAgICAiYWN0aXZlIFAgLSBsb3cgcHJpbWVkIEUiLAogICAgICAgICAgICAgICAgICAgICAgICAiUEMgUCAtIHVubWFya2VkIFBJUiIsCiAgICAgICAgICAgICAgICAgICAgICAgICJpbmFjdGl2ZSBQIC0gdW5tYXJrZWQgUElSIiwKICAgICAgICAgICAgICAgICAgICAgICAgImluYWN0aXZlIFAgLSBsb3cgcHJpbWVkIEUsIENUQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAicHJpbWVkIEUiLAogICAgICAgICAgICAgICAgICAgICAgICAicG9pc2VkIEUiLAogICAgICAgICAgICAgICAgICAgICAgICAiYWN0aXZlIFAgLSBhY3RpdmUgUCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJhY3RpdmUgUCAtIGFjdGl2ZSBFIgogICAgICAgICAgICAgICAgICAgICAgICApCmNsdXN0ZXJfZ3JvdXBfY29sb3VycyA8LSBjKCIjYjc4NWJiIiwgIiM1M2MyYjMiLCAiI2JmNmM2YyIsICIjYjJiNWI1IiwgIiM3NDExMTMiLCAiI2VhY2E0OCIsICIjY2EzNTI2IiwgIiM5MWM3NDAiLCAiIzI1MmQzNyIpCm5hbWVzKGNsdXN0ZXJfZ3JvdXBfY29sb3VycykgPC0gY2x1c3Rlcl9ncm91cF9uYW1lcwpgYGAKClBsb3R0aW5nIG9yaWdpbmFsIHN1bW1hcmlzZWQgbWFya3MKCmBgYHtyfQoKbWFya3NfMiAlPiUgCiAgbXV0YXRlKGNsdXN0ZXJfZ3JvdXAgPSBnc3ViKCJpbmFjdGl2ZSBQIC0gbG93IHByaW1lZCBFIiwgImFjdGl2ZSBQIC0gbG93IHByaW1lZCBFIiwgY2x1c3Rlcl9ncm91cCkpICU+JSAKICBtdXRhdGUoY2x1c3Rlcl9ncm91cCA9IGdzdWIoImFjdGl2ZSBQIC0gbG93IHByaW1lZCBFLCBDVENGIiwgImluYWN0aXZlIFAgLSBsb3cgcHJpbWVkIEUsIENUQ0YiLCBjbHVzdGVyX2dyb3VwKSkgJT4lIAogIHNsaWNlX3NhbXBsZShwcm9wID0gMC4xKSAlPiUgCiAgZ2dwbG90KGFlcyhVTUFQMSwgVU1BUDIsIGNvbG91ciA9IGNsdXN0ZXJfZ3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsKICBnZ3RpdGxlKCJFTSBjbHVzdGVycyIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoLTEwLCAxMiksIHlsaW0gPSBjKC0xMCwgOCkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNsdXN0ZXJfZ3JvdXBfY29sb3VycykgKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSAKYGBgCgoKU3VtbWFyaXNpbmcgTG91dmFpbiBjbHVzdGVycwooVGhpcyBvbmUgaXMgZm9yIGRpbSAxMiwgcmVzb2x1dGlvbiAxKQoKYGBge3J9ClBfdW5tYXJrZWRQSVIgPC0gYygiMiIsICI1IiwgIjEzIiwgIjE1IikKYWN0aXZlX2xvd3ByaW1lZCA8LSBjKCI5IiwgIjE2IikKUENfUF91bm1hcmtlZCA8LSBjKCIwIiwgIjEyIiwgIjE3IikKaW5hY3RpdmVfdW5tYXJrZWQgPC0gYygiMyIsICI0IiwgIjciLCAiOSIsICIxMCIsICIxNCIpCmluYWN0aXZlX2xvd3ByaW1lZENUQ0YgPC0gYygiMSIsICIxOSIpCnByaW1lZCA8LSBjKCIyMCIsICI2IikKcG9pc2VkIDwtIGMoICIxOCIpCnBfcCA8LSBjKCIxMSIpCmFjdGl2ZV9hY3RpdmVFIDwtIGMoIjgiKQpgYGAKCgpgYGB7cn0KbWFya3NfMiAlPiUgCiAgZmlsdGVyKCFMb3V2YWluX2NsdXN0ZXJfSUQgJWluJSBleGNsdWRlZF9jbHVzdGVycykgJT4lIAogIG11dGF0ZShMb3V2YWluX2NsdXN0ZXJfZ3JvdXAgPSBjYXNlX3doZW4oTG91dmFpbl9jbHVzdGVyX0lEICVpbiUgUF91bm1hcmtlZFBJUiB+ICJhY3RpdmUgUCAtIHVubWFya2VkIFBJUiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb3V2YWluX2NsdXN0ZXJfSUQgJWluJSBhY3RpdmVfbG93cHJpbWVkIH4gImFjdGl2ZSBQIC0gbG93IHByaW1lZCBFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIFBDX1BfdW5tYXJrZWQgfiAiUEMgUCAtIHVubWFya2VkIFBJUiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb3V2YWluX2NsdXN0ZXJfSUQgJWluJSBpbmFjdGl2ZV91bm1hcmtlZCB+ICJpbmFjdGl2ZSBQIC0gdW5tYXJrZWQgUElSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIGluYWN0aXZlX2xvd3ByaW1lZENUQ0YgfiAiaW5hY3RpdmUgUCAtIGxvdyBwcmltZWQgRSwgQ1RDRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb3V2YWluX2NsdXN0ZXJfSUQgJWluJSBwcmltZWQgfiAicHJpbWVkIEUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG91dmFpbl9jbHVzdGVyX0lEICVpbiUgcG9pc2VkIH4gInBvaXNlZCBFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIHBfcCB+ICJhY3RpdmUgUCAtIGFjdGl2ZSBQIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvdXZhaW5fY2x1c3Rlcl9JRCAlaW4lIGFjdGl2ZV9hY3RpdmVFIH4gImFjdGl2ZSBQIC0gYWN0aXZlIEUiKSkgLT4gbWFya3NfMwpgYGAKClBsb3R0aW5nIExvdXZhaW4gc3VtbWFyaXNlZCBtYXJrcwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0ID0gNH0KbWFya3NfMyAlPiUgCiAgc2xpY2Vfc2FtcGxlKHByb3AgPSAwLjA1KSAlPiUgCiAgZ2dwbG90KGFlcyhVTUFQMSwgVU1BUDIsIGNvbG91ciA9IExvdXZhaW5fY2x1c3Rlcl9ncm91cCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKwogIGdndGl0bGUoIkxvdXZhaW4gY2x1c3RlcnMiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC0xMCwgMTIpLCB5bGltID0gYygtMTAsIDgpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjbHVzdGVyX2dyb3VwX2NvbG91cnMpICsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSAtPiBVTUFQX0xvdXZhaW5fY2x1c3RlcnMKClVNQVBfTG91dmFpbl9jbHVzdGVycwpgYGAKRXhwb3J0aW5nCgpgYGB7cn0KZ2dzYXZlKCIuLi9vdXRwdXQvcGxvdHMvVU1BUF9Mb3V2YWluX2NsdXN0ZXJzLnBuZyIsIFVNQVBfTG91dmFpbl9jbHVzdGVycywgaGVpZ2h0ID0gNCwgd2lkdGggPSA4LCB1bml0cyA9ICJpbiIpCmdnc2F2ZSgiLi4vb3V0cHV0L3Bsb3RzL1VNQVBfTG91dmFpbl9jbHVzdGVycy5zdmciLCBVTUFQX0xvdXZhaW5fY2x1c3RlcnMsIGhlaWdodCA9IDQsIHdpZHRoID0gOCwgdW5pdHMgPSAiaW4iKQpgYGAKCgoKU29tZSBjbHVzdGVycyBhcmUgc3Ryb25nIGFuZCBlc3NlbnRpYWxseSBwb3AgdXAgaW4gYWxsIGNsdXN0ZXIgY29uZGl0aW9uczoKCi0gcG9seWNvbWIgcHJvbW90ZXJzCi0gcG9pc2VkIGVuaGFuY2VycwotIGluYWN0aXZlIFAgLSBDVENGCi0gYWN0aXZlIFAgLSBhY3RpdmUgUCwgYWx0aG91Z2ggdGhpcyBvbmUgbWl4ZXMgZWFzaWx5IHdpdGggdGhlIGFjdGl2ZSBQIGFjdGl2ZSBFIGNsdXN0ZXIgZGVzcGl0ZSBiZWluZyBxdWl0ZSBkZWZpbmVkIG9uIHRoZSBVTUFQCi0gd2UgdGhlbiBoYXZlIHRoZSB2YXJpb3VzIGNsdXN0ZXJzIHRoYXQgZm9ybSB0aGUgJ2JvZHknIG9mIHRoZSBVTUFQIHdoaWNoIGFyZW4ndCBjbGVhcmx5IGRlZmluZWQuIFRoZXkgaGF2ZSB2YXJpb3VzIGxldmVscyBvZiBLMjdhYyBhdCBQIGFuZCBQSVIgYW5kIGFyZSB0aGVyZWZvcmUgbGFiZWxsZWQgYXMgbG93IHByaW1lZCBlbmhhbmNlcnMsIGFjdGl2ZSBlbmhhbmNlcnMsIGFjdGl2ZSBhbmQgaW5hY3RpdmUgcHJvbW90ZXJzLiBNYXliZSB3ZSBzaG91bGQgYmUgY2xlYXJlciBhYm91dCB0aGlzIGluIHRoZSB0ZXh0LgoKRXhwb3J0aW5nIHRoZSBjbHVzdGVycwoKYGBge3J9Cm1hcmtzXzIgJT4lIAogIHNlbGVjdChpbnRlcmFjdGlvbl9JRCwgTG91dmFpbl9jbHVzdGVyX0lEKSAlPiUgCiAgd3JpdGVfdHN2KCIuLi9vdXRwdXQvdGFibGVzL0xvdXZhaW5fY2x1c3Rlcl9hc3NpZ25tZW50LnRzdiIpCmBgYAoKCg==